package com.xyy.saas.payment.query.core.service;

import com.alibaba.fastjson.JSON;
import com.jddglobal.open.response.base.SpiResponse;
import com.xyy.saas.payment.adpater.RouteManager;
import com.xyy.saas.payment.adpater.impl.JdCreditAdapter;
import com.xyy.saas.payment.adpater.impl.PinganAdapter;
import com.xyy.saas.payment.adpater.impl.WxAdapter;
import com.xyy.saas.payment.adpater.jdCredit.req.QueryOrderReq;
import com.xyy.saas.payment.common.Constants;
import com.xyy.saas.payment.common.exception.PaymentException;
import com.xyy.saas.payment.cores.bo.QueryPayNoResultBo;
import com.xyy.saas.payment.cores.bo.QueryResultBo;
import com.xyy.saas.payment.cores.enums.ResultCodeEnum;
import com.xyy.saas.payment.cores.vo.QueryPayVo;
import com.xyy.saas.payment.cores.vo.ResultVO;
import com.xyy.saas.payment.dao.mapper.PayResultOrderMapper;
import com.xyy.saas.payment.dao.mapper.RefundOrderMapper;
import com.xyy.saas.payment.dao.mapper.WithdrawOrderMapper;
import com.xyy.saas.payment.dao.model.PayResultOrder;
import com.xyy.saas.payment.dao.model.PrePayOrder;
import com.xyy.saas.payment.dao.model.RefundOrder;
import com.xyy.saas.payment.dao.model.WithdrawOrder;
import com.xyy.saas.payment.payment.core.service.PrePayOrderService;
import com.xyy.saas.payment.service.PayResultOrderService;
import com.xyy.saas.payment.util.ApolloUtil;
import com.xyy.saas.payment.util.DateUtil;
import com.xyy.saas.payment.util.JSONUtils;
import com.xyy.saas.payment.util.SignUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;

@Service
@DependsOn("apolloUtil")
@Slf4j
public class QueryTradeService {

    private static final Logger LOGGER = LoggerFactory.getLogger(QueryTradeService.class);

    @Resource
    private RouteManager routeManager;

    @Resource
    private RefundOrderMapper refundDomainMapper;

    @Resource
    private WithdrawOrderMapper withdrawOrderMapper;

    @Autowired
    private PrePayOrderService prePayOrderService;

    @Autowired
    private PayResultOrderService payResultOrderService;

    @Autowired
    private WxAdapter wxAdapter;
    @Autowired
    private JdCreditAdapter jdCreditAdapter;

    @Resource
    private PayResultOrderMapper payResultOrderMapper;

    public SpiResponse queryOrderInfo(QueryOrderReq queryOrderReq) throws PaymentException {

        return jdCreditAdapter.queryOrderInfo(queryOrderReq);
    }

    public ResultVO<QueryResultBo> checkPay(String tradeNo, String channel, String businessOrderType, String payType) throws PaymentException {
        if (StringUtils.isBlank(tradeNo) || tradeNo.length() > Constants.MAX_STRING_LENGTH_NO) {
            throw new PaymentException(ResultCodeEnum.PARAM_ERROR);
        }
        // 先查数据库
        PrePayOrder prePayOrder = prePayOrderService.getPrePayOrderByPayNo(tradeNo);
        if (prePayOrder == null) {
            throw new PaymentException(ResultCodeEnum.TRADE_NOT_EXIT_ERROR);
        }
        PayResultOrder payResultOrder = payResultOrderService.selectByPayNoAndChannel(prePayOrder.getPayNo(), channel);
        QueryResultBo bo = new QueryResultBo();
        // 订单已支付
        if (payResultOrder != null) {
            bo.setStatus(QueryResultBo.STATUS_FINISHED);
            return ResultVO.createSuccess(bo);
        }
        String realChannel = "";
        if (Constants.thirdChannelSubmitPingan(channel)) {
            realChannel = channel;
        } else {
            if (channel.startsWith(Constants.CHANNEL_AGGREGATE_NAME)) {
                realChannel = Constants.CHANNEL_AGGREGATE_NAME;
            } else {
                realChannel = channel;
            }
        }
        // 如果是未支付状态，去第三方查支付单
        bo = routeManager.queryPayStatus(prePayOrder.getPayNo(), realChannel, prePayOrder, payType);
        if (QueryResultBo.STATUS_PROCESSING.equals(bo.getStatus())) {
            bo.setStatus(QueryResultBo.STATUS_PROCESSING);
            return ResultVO.createSuccess(bo);
        }
        // 状态改变，更新数据库
        if (QueryResultBo.STATUS_FINISHED.equals(bo.getStatus())) {
            bo.setStatus(QueryResultBo.STATUS_FINISHED);
            PayResultOrder payResultOrder1 = new PayResultOrder();
            payResultOrder1.setCtime(new Date(bo.getSuccessTime()*1000));
            payResultOrder1.setUtime(new Date());
            payResultOrder1.setReceiveId(prePayOrder.getReceiverId());
            payResultOrder1.setAmount(prePayOrder.getAmount());
            payResultOrder1.setFee(0);
            payResultOrder1.setBusinessOrderType(prePayOrder.getBusinessOrderType());
            payResultOrder1.setBusinessType(prePayOrder.getBusinessType());
            payResultOrder1.setPayChannel(channel);
            payResultOrder1.setChannelChargeNo(bo.getChannelChargeNo());
            payResultOrder1.setPayNo(prePayOrder.getPayNo());
            int count = payResultOrderService.insertSelective(payResultOrder1);
            if (count < 1) {
                LOGGER.error("QueryTradeService checkPay payResultOrderService.insertSelective error payResultOrder:{}", JSON.toJSON(payResultOrder1));
                bo.setStatus(QueryResultBo.STATUS_PROCESSING);
                return ResultVO.createSuccess(bo);
            }
        }
        return ResultVO.createSuccess();
    }
    public ResultVO<QueryResultBo> queryChannelPayStatus(String tradeNo, String channel, String businessOrderType, String payType) throws PaymentException {
        if (StringUtils.isBlank(tradeNo) || tradeNo.length() > Constants.MAX_STRING_LENGTH_NO) {
            throw new PaymentException(ResultCodeEnum.PARAM_ERROR);
        }
        // 先查数据库
        PrePayOrder prePayOrder = prePayOrderService.getPrePayOrderByPayNo(tradeNo);
        if (prePayOrder == null) {
            throw new PaymentException(ResultCodeEnum.TRADE_NOT_EXIT_ERROR);
        }
        PayResultOrder payResultOrder = payResultOrderService.selectByPayNoAndChannel(prePayOrder.getPayNo(), channel);
        QueryResultBo bo = new QueryResultBo();
        // 订单已支付
        if (payResultOrder != null) {
            bo.setStatus(QueryResultBo.STATUS_FINISHED);
            return ResultVO.createSuccess(bo);
        }
        String realChannel = "";
        if (Constants.thirdChannelSubmitPingan(channel)) {
            realChannel = channel;
        } else {
            if (channel.startsWith(Constants.CHANNEL_AGGREGATE_NAME)) {
                realChannel = Constants.CHANNEL_AGGREGATE_NAME;
            } else {
                realChannel = channel;
            }
        }
        // 如果是未支付状态，去第三方查支付单
        bo = routeManager.queryPayStatus(prePayOrder.getPayNo(), realChannel, prePayOrder, payType);
        return ResultVO.createSuccess(bo);
    }
    public ResultVO<List<QueryPayNoResultBo>> queryPay(QueryPayVo queryPayVo) {
        List<PayResultOrder> list = payResultOrderService.selectListByPayNo(queryPayVo.getTradeNo());
        if(list == null || list.size() == 0) {
            return ResultVO.createSuccess();
        }
        List<QueryPayNoResultBo> results = new ArrayList<>();
        for(PayResultOrder payResultOrder : list) {
            QueryPayNoResultBo queryPayNoResultBo = new QueryPayNoResultBo();
            queryPayNoResultBo.setAmount(payResultOrder.getAmount());
            queryPayNoResultBo.setChannel(payResultOrder.getPayChannel());
            queryPayNoResultBo.setChannelChargeNo(payResultOrder.getChannelChargeNo());
            queryPayNoResultBo.setSuccessTime(payResultOrder.getCtime().getTime() / 1000);
            results.add(queryPayNoResultBo);
        }
        return ResultVO.createSuccess(results);
    }

    public ResultVO<QueryResultBo> queryRefund(String tradeNo) throws PaymentException {
        return queryRefund(tradeNo, null);
    }

    public ResultVO<QueryResultBo> queryRefund(String tradeNo, String businessOrderNo) throws PaymentException {
        if (StringUtils.isBlank(tradeNo) && StringUtils.isBlank(businessOrderNo)) {
            throw new PaymentException(ResultCodeEnum.PARAM_ERROR);
        }

        //从数据库获取退款单对应的支付单id
        RefundOrder refundOrder = StringUtils.isNotBlank(tradeNo) ? refundDomainMapper.selectByRefundNo(tradeNo) :
                refundDomainMapper.selectByBusinessRefundNo2(businessOrderNo);

        if(refundOrder == null) {
            throw new PaymentException(ResultCodeEnum.TRADE_NOT_EXIT_ERROR);
        }

        QueryResultBo bo = null;

        //先检查退款单状态
        if (RefundOrder.STATUS_FINISH.equals(refundOrder.getStatus())) {
            // 退款成功
            bo = buildQueryResultBO(QueryResultBo.STATUS_FINISHED, refundOrder.getAmount(), 0, refundOrder.getSuccessTime());
        }
        else {
            bo = queryChannelRefundStatus(refundOrder, refundOrder.getBusinessType());
        }

        return ResultVO.createSuccess(bo);
    }

    public QueryResultBo queryChannelRefundStatus(RefundOrder refundOrder, String businessOrderType) throws PaymentException {
        QueryResultBo bo = routeManager.queryRefundStatus(refundOrder, businessOrderType, refundOrder.getChannel());

        if(bo == null) {
            return buildQueryResultBO(QueryResultBo.convertStatus(refundOrder.getStatus()), refundOrder.getAmount(), 0, Constants.DEFAULT_DATE);
        }

        //如果状态变了 更新数据库
        if(QueryResultBo.STATUS_PROCESSING.equals(bo.getStatus())) {
            refundOrder.setStatus(RefundOrder.STATUS_IN);
        }
        else if (QueryResultBo.STATUS_FINISHED.equals(bo.getStatus())) {
            refundOrder.setStatus(RefundOrder.STATUS_FINISH);
            refundOrder.setSuccessTime(DateUtil.unixToDate(bo.getSuccessTime()));
            PayResultOrder payResultOrder = payResultOrderMapper.selectByPayNoAndChannel(refundOrder.getPayNo(), refundOrder.getChannel());

            if(payResultOrder == null) {
                throw new PaymentException(ResultCodeEnum.TRADE_NOT_EXIT_ERROR);
            }
        }
        else if(QueryResultBo.STATUS_FAILED.equals(bo.getStatus())) {
            refundOrder.setStatus(RefundOrder.STATUS_FAIL);
        }

        if(!StringUtils.isBlank(bo.getChannelChargeNo())) {
            refundOrder.setChannelRefundNo(bo.getChannelChargeNo());
        }

        refundOrder.setUpdateTime(new Date());
        if (StringUtils.isNotBlank(refundOrder.getChannel())
                && refundOrder.getChannel().contains("pingan")
                && refundOrder.getStatus() != RefundOrder.STATUS_FINISH) {
            refundOrder.setUpdateTime(null);
        }
        refundDomainMapper.updateByPrimaryKeySelective(refundOrder);
        return bo;
    }

    public ResultVO<QueryResultBo> queryWithdraw(String tradeNo) throws PaymentException {
        if (StringUtils.isBlank(tradeNo) || tradeNo.length() > Constants.MAX_STRING_LENGTH_NO) {
            throw new PaymentException(ResultCodeEnum.PARAM_ERROR);
        }
        WithdrawOrder withdrawOrder = withdrawOrderMapper.selectByWithdrawNo(tradeNo);
        if (withdrawOrder == null) {
            throw new PaymentException(ResultCodeEnum.TRADE_NOT_EXIT_ERROR);
        }
        QueryResultBo bo = new QueryResultBo();
        // 提现已完成
        if (WithdrawOrder.STATUS_FINISH.equals(withdrawOrder.getStatus())) {
            bo = buildQueryResultBO(QueryResultBo.STATUS_FINISHED, withdrawOrder.getAmount(), withdrawOrder.getFee(), withdrawOrder.getSuccessTime());
        } else if (WithdrawOrder.STATUS_FAIL.equals(withdrawOrder.getStatus())) {
            // 提现失败
            bo = buildQueryResultBO(QueryResultBo.STATUS_FAILED, withdrawOrder.getAmount(), withdrawOrder.getFee(), Constants.DEFAULT_DATE);
        }
        // 如果状态是提现中，就发起重试
        else if (WithdrawOrder.STATUS_IN.equals(withdrawOrder.getStatus())) {
            bo = buildQueryResultBO(QueryResultBo.STATUS_PROCESSING, withdrawOrder.getAmount(), withdrawOrder.getFee(), Constants.DEFAULT_DATE);
        } else {
            LOGGER.error("QueryTradeService#queryWithdraw unknown status:{}", withdrawOrder.getStatus());
            throw new PaymentException(ResultCodeEnum.DEFAULT_ERROR);
        }
        return ResultVO.createSuccess(bo);
    }

    private QueryResultBo buildQueryResultBO(String status, Integer amount, Integer fee, Date time) {
        QueryResultBo bo = new QueryResultBo();
        bo.setStatus(status);
        bo.setAmount(amount);
        bo.setFee(fee);
        bo.setSuccessTime(time.getTime() / 1000);
        return bo;
    }

    public boolean checkRequestSign(String tradeNo, String invoker, String sign) {
        Map<String, Object> map = new HashMap<>(2);
        map.put("tradeNo", tradeNo);
        map.put("invoker", invoker);
        String publicKey = ApolloUtil.getProperty(invoker + ".public_key");
        return SignUtil.doCheck(map, sign, publicKey);
    }

    /**
     * 退款重试
     * @param refundOrder
     * @throws PaymentException
     */
    public void retryRefundOrder(RefundOrder refundOrder) throws PaymentException {
        PayResultOrder payResultOrder = payResultOrderService.selectByPayNoAndChannel(refundOrder.getPayNo(), refundOrder.getChannel());
        if (payResultOrder == null) {
            throw new PaymentException(ResultCodeEnum.TRADE_NOT_EXIT_ERROR);
        }
        if( Constants.CHANNEL_WX_NAME.equals(payResultOrder.getPayChannel())) {
            wxAdapter.retryRefund(payResultOrder, refundOrder);
        } else {
            LOGGER.error("QueryTradeService#retryRefundOrder cannot execute retry refundOrder:{}", JSONUtils.toJSON(refundOrder));
        }
    }
}
